;(function ($) {
    'use strict';

    $.dateTime = Class.create();

    $.extend(true, $.dateTime.prototype, {

        defaultControlDOMType: 'signle',
        $panel: null,

        options: {
            controlType: null,
            display: {
                week: true,
            },
            lang: 'zh-CN',
            format: 'yyyy-MM-dd HH:mm:ss',
        },

        local: {
            weekday: null,
            months: null,
        },

        initYear: new Date().getFullYear(),

        initMonth: new Date().getMonth(),

        selected: {
            selectedDay: null,
            selectedYear: null,
            selectedMonth: null,
        },

        date: {
            min_date: '1970-01-01',
            max_date: '2470-12-31',
            today: new Date()
        },

        _defaultClasses: {
            panelContainer: 'dt-dateTime-panel-container',
            yearInput: 'dt-dateTime-year',
            monthInput: 'dt-dateTime-month',
            weekdayContainer: 'dt-dateTime-week-container',
            weekBtn: 'dt-dateTime-week_btn',
            weekdayBtn: 'dt-dateTime-week_weekday',
            daysContainer: 'dt-dateTime-date-container',
            dayContainer: 'dt-dateTime-date',
            dayBtn: 'dt-dateTime-date_btn',
            dayBtnPreMonth: 'dt-dateTime-date_btn_preMonth',
            dayBtnWeekDay: 'dt-dateTime-date_btn_weekday',
            arrow: 'dt-date-arrow',
        },

        _defaultProperty: {
            arrowPreYear: 'dt-data-arrow',
        },

        // 获取input框模板
        _getInputDOMTemplate: {
            single() {
                return `<div class="dt-dateTime">
                            <div class="dt-dateTime-container dt-dateTime-outLined">
                                <div class="dt-dateTime-input">
                                    <input type="text" placeholder="请选择日期" readonly>
                                    <span class="dt-dateTime-suffix">
                                        <span class="dt-dateTime-icon">
                                            <svg viewBox="64 64 896 896" t="1706066317970" class="icon" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5157" width="16"><path d="M875.971388 141.872812H729.734971V88.685814c0-18.445135-14.949799-33.394934-33.394934-33.394935s-33.394934 14.949799-33.394934 33.394935v53.186998h-291.315143V88.685814c0-18.445135-14.949799-33.394934-33.394934-33.394935s-33.394934 14.949799-33.394935 33.394935v53.186998H158.592543c-56.437439 0-102.355473 45.918035-102.355474 102.355474v648.206805c0 56.437439 45.918035 102.355473 102.355474 102.355473h717.378845c56.437439 0 102.355473-45.918035 102.355474-102.355473V244.228286c0-56.437439-45.918035-102.355473-102.355474-102.355474z m-717.378845 66.789869h717.378845c19.613958 0 35.565605 15.951647 35.565605 35.565605v81.817589H123.026938v-81.817589c0-19.613958 15.951647-35.565605 35.565605-35.565605z m717.378845 719.338015H158.592543c-19.613958 0-35.565605-15.951647-35.565605-35.565605V392.835743h788.510055v499.610479c0 19.613958-15.951647 35.565605-35.565605 35.565605zM341.218306 516.296815c0 18.445135-14.949799 33.394934-33.394934 33.394934h-63.21661c-18.445135 0-33.394934-14.949799-33.394935-33.394934s14.949799-33.394934 33.394935-33.394934h63.21661c18.445135 0 33.394934 14.949799 33.394934 33.394934z m0 142.306946c0 18.445135-14.949799 33.394934-33.394934 33.394935h-63.21661c-18.445135 0-33.394934-14.949799-33.394935-33.394935s14.949799-33.394934 33.394935-33.394934h63.21661c18.445135 0 33.394934 14.949799 33.394934 33.394934z m0 142.306947c0 18.445135-14.949799 33.394934-33.394934 33.394934h-63.21661c-18.445135 0-33.394934-14.949799-33.394935-33.394934s14.949799-33.394934 33.394935-33.394935h63.21661c18.445135 0 33.394934 14.949799 33.394934 33.394935z m253.178128-284.502577c0 18.445135-14.949799 33.394934-33.394934 33.394935h-63.21661c-18.445135 0-33.394934-14.949799-33.394935-33.394935s14.949799-33.394934 33.394935-33.394934h63.21661c18.445135 0 33.394934 14.949799 33.394934 33.394934z m0 142.306947c0 18.445135-14.949799 33.394934-33.394934 33.394934h-63.21661c-18.445135 0-33.394934-14.949799-33.394935-33.394934s14.949799-33.394934 33.394935-33.394935h63.21661c18.445135 0 33.394934 14.949799 33.394934 33.394935z m0 142.306946c0 18.445135-14.949799 33.394934-33.394934 33.394934h-63.21661c-18.445135 0-33.394934-14.949799-33.394935-33.394934s14.949799-33.394934 33.394935-33.394934h63.21661c18.445135 0 33.394934 14.949799 33.394934 33.394934z m253.178128-284.502576c0 18.445135-14.949799 33.394934-33.394934 33.394934h-63.21661c-18.445135 0-33.394934-14.949799-33.394935-33.394934s14.949799-33.394934 33.394935-33.394934h63.21661c18.445135 0 33.394934 14.949799 33.394934 33.394934z m0 142.306946c0 18.445135-14.949799 33.394934-33.394934 33.394934h-63.21661c-18.445135 0-33.394934-14.949799-33.394935-33.394934s14.949799-33.394934 33.394935-33.394934h63.21661c18.445135 0 33.394934 14.949799 33.394934 33.394934z m0 142.306947c0 18.445135-14.949799 33.394934-33.394934 33.394934h-63.21661c-18.445135 0-33.394934-14.949799-33.394935-33.394934s14.949799-33.394934 33.394935-33.394935h63.21661c18.445135 0 33.394934 14.949799 33.394934 33.394935z" p-id="5158" fill="#2fd43a"></path></svg>
                                        </span>
                                    </span>
                                </div>
                            </div>
                        </div>`
            },

            range() {

            },

            year() {

            },

            month() {

            }
        },

        // 获取一些DOM
        _getDOMS: {
            _getYearArrowPrevDOM() {
                return `<button type="button" class="dt-date-arrow dt-dateTime-year-prev" dt-data-arrow="pre_year">
                        <span class="dt-dateTime-arrow">
                            <svg t="1706151158881" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8117" width="24"><path d="M550.4 494.933333l192 192 29.866667-29.866666-162.133334-162.133334 162.133334-162.133333-29.866667-29.866667-192 192z m-256 0l192 192 29.866667-29.866666-162.133334-162.133334 162.133334-162.133333-29.866667-29.866667-192 192z" fill="#444444" p-id="8118"></path></svg>
                        </span>
                    </button>`
            },

            _getMonthArrowNextDOM() {
                return `<button type="button" class="dt-date-arrow dt-dateTime-month-next" dt-data-arrow="next_month">
                        <span class="dt-dateTime-arrow">
                            <svg t="1706152366635" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8425" width="24"><path d="M644.266667 494.933333l-192 192-29.866667-29.866666 162.133333-162.133334-162.133333-162.133333 29.866667-29.866667 192 192z" fill="#444444" p-id="8426"></path></svg>
                        </span>
                    </button>`
            },

            _getMonthArrowPrevDOM() {
                return `<button type="button" class="dt-date-arrow dt-dateTime-month-prev" dt-data-arrow="pre_month">
                        <span class="dt-dateTime-arrow">
                            <svg t="1706152294626" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8271" width="24"><path d="M384 512l192 192 29.866667-29.866667-162.133334-162.133333 162.133334-162.133333-29.866667-29.866667L384 512z" fill="#444444" p-id="8272"></path></svg>
                        </span>
                  </button>`
            },

            _getYearArrowNextDOM() {
                return `<button type="button" class="dt-date-arrow dt-dateTime-year-next" dt-data-arrow="next_year">
                        <span class="dt-dateTime-arrow">
                            <svg t="1706151119685" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7963" width="24"><path d="M516.266667 494.933333l-192 192-29.866667-29.866666 162.133333-162.133334-162.133333-162.133333 29.866667-29.866667 192 192z m256 0l-192 192-29.866667-29.866666 162.133333-162.133334-162.133333-162.133333 29.866667-29.866667 192 192z" fill="#444444" p-id="7964"></path></svg>
                        </span>
                    </button>`
            },

            _getYearDOM() {
                return `<button type="button" class="dt-dateTime-year"></button>`
            },

            _getMonthDOM() {
                return `<button type="button" class="dt-dateTime-month"></button>`
            },

            _getWeeksDOM() {
                // 周末：dt-dateTime-week_weekday
                return `<div class="dt-dateTime-week-container"></div>`
            },

            _getDaysDOM() {
                return `<div class="dt-dateTime-date-container"></div>`
            },

            _getTimeDOM() {
                return `<div class="dt-dateTime-time-container"></div>`
            },

        },

        // 获取面板模板
        _getDateTimeDOMTemplate: {
            single() {
                return `<div class="dt-dateTime-panel-container">
                            <div class="dt-dateTime-panel-layout">
                                <div class="dt-dateTime-panel-column">
                                    <div class="dt-dateTime-panel-date-container">
                                        <div class="dt-dateTime-panel-date-header">
                                            <# YearArrowPrev #>
                                            <# MonthArrowPrev #>
                                            <div class="dt-dateTime-panel-date-header_content">
                                                <# Year #>
                                                <# Month #>
                                            </div>
                                            <# MonthArrowNext #>
                                            <# YearArrowNext #>
                                        </div>
                                        <div class="dt-dateTime-date-wrapper">
                                            <# Weeks #> 
                                            <# Days #>
                                        </div>
                                    </div>
                                    <# Time #>
                                </div>
                            </div>
                        </div>`
            },
        },

        /**
         * 初始化
         */
        initialize(dtTimeContainer, props) {
            this.container = dtTimeContainer.find('.dt-dateTime').get(0);

            this._init(dtTimeContainer, props);
        },

        /**
         * @param dtTimeContainer 控件容器DOM
         * @param props 入参配置
         * @private
         */
        _init(dtTimeContainer, props) {
            this.firstInit = true;
            this.options.controlType = props.type;
            this._initLocalDate();
            this._create(dtTimeContainer);
            this._initEvents();
        },

        /**
         * 时间戳格式化工具
         * @param timestamp
         * @param template
         * @returns {*}
         * @private
         */
        _formatDateTime(timestamp, template) {
            let date = new Date(timestamp);
            let year = date.getFullYear();
            let month = ('0' + (date.getMonth() + 1)).slice(-2);
            let day = ('0' + date.getDate()).slice(-2);
            let hour = ('0' + date.getHours()).slice(-2);
            let minute = ('0' + date.getMinutes()).slice(-2);
            let second = ('0' + date.getSeconds()).slice(-2);

            return template.replace('yyyy', year)
                .replace('MM', month)
                .replace('dd', day)
                .replace('HH', hour)
                .replace('mm', minute)
                .replace('ss', second);
        },

        /**
         * 初始化本地日期
         * @private
         */
        _initLocalDate() {
            this.local.months = [];
            this.local.weekday = [];

            for (let i = 0; i < 7; i++) {
                const weekday = new Date(0, 0, i).toLocaleString(this.options.lang, {weekday: 'short'});
                this.local.weekday.push(weekday);
            }
            for (let i = 0; i < 12; i++) {
                const month = new Date(0, i).toLocaleString(this.options.lang, {month: 'long'});
                this.local.months.push(month);
            }
        },

        /**
         * 创建控件内组件
         * @param dtTimeContainer
         * @private
         */
        _create(dtTimeContainer) {
            var _this = this;
            const controlType = {
                single: () => {
                    _this._createWeekDay();
                    _this._createDays();
                },
            }

            this._createPanel(dtTimeContainer);
            this._visibilityHeader();
            controlType[this.options.controlType || this.defaultControlDOMType]();
        },

        /**
         * 创建面板
         * @private
         */
        _createPanel(dtTimeContainer) {
            const panelTemplate = this._getDateTimeDOMTemplate[this.options.controlType || this.defaultControlDOMType]();
            dtTimeContainer.append(this._DOMParser(panelTemplate));
            this.$panel = dtTimeContainer.find(`.${this._defaultClasses.panelContainer}`);
        },

        /**
         * 显示年和月
         * @private
         */
        _visibilityHeader() {
            let year, month, date;
            let $yearInput = this.$panel.find(`.${this._defaultClasses.yearInput}`);
            let $monthInput = this.$panel.find(`.${this._defaultClasses.monthInput}`);

            if (!$yearInput.length || !$monthInput.length) return;

            year = this.selected.selectedYear == null ? this.initYear : this.selected.selectedYear;
            month = this.selected.selectedMonth == null ? this.initMonth : this.selected.selectedMonth;
            date = new Date(year, month, 1);

            this._visibilityYear($yearInput, date);
            this._visibilityMonth($monthInput, date);

        },

        /**
         * 显示年份
         * @param $yearInput
         * @param date
         * @private
         */
        _visibilityYear($yearInput, date) {
            const year = date.getFullYear();

            $yearInput.attr("data-selected-year", year);
            $yearInput.text(year + '年');
        },

        /**
         * 显示月份
         * @param $monthInput
         * @param date
         * @private
         */
        _visibilityMonth($monthInput, date) {
            const month = date.getMonth();

            $monthInput.attr("data-selected-month", month);
            $monthInput.text(this.local.months[month]);
        },

        /**
         * 创建周
         * @private
         */
        _createWeekDay() {
            if (!this.local.weekday.length) return;

            var _this = this;
            const $weekdayContainers = this.$panel.find(`.${this._defaultClasses.weekdayContainer}`);
            $.each($weekdayContainers, (index, weekdayContainer) => {
                /* 清除周容器中的内容 */
                $(weekdayContainer).html('');

                $.each(_this.local.weekday, (_index, _weekday) => {
                    const $weekdayItem = $('<span>');
                    const styleClass = _index == 5 || _index == 6 ? `${_this._defaultClasses.weekBtn} ${_this._defaultClasses.weekdayBtn}`
                        : `${_this._defaultClasses.weekBtn}`;
                    $weekdayItem.addClass(styleClass);
                    $weekdayItem.text(_this.local.weekday[_index]);
                    $(weekdayContainer).append($weekdayItem);
                })
            })
        },

        /**
         * 创建日期
         * @private
         */
        _createDays() {
            var _this = this;

            const $daysContainers = this.$panel.find(`.${this._defaultClasses.daysContainer}`);
            if (!$daysContainers.length) { return; }

            let year,month;
            const controlType = this.controlType || this.defaultControlDOMType;
            $.each($daysContainers, (index, daysContainer) => {
                if (controlType == 'signle') {
                    year = _this.selected.selectedYear == null ? _this.initYear : _this.selected.selectedYear;
                    month = _this.selected.selectedMonth == null ? _this.initMonth : _this.selected.selectedMonth;
                } else if (controlType == '') {}

                $(daysContainer).html('');

                const firstDay = new Date(year, month, 1);
                const daysOfMonth = new Date(year, month + 1, 0).getDate();
                const firstDayWeek = (firstDay.getDay() !== 0 ? firstDay.getDay() : 7) - 1;
                const totalsDays = firstDayWeek + daysOfMonth;

                _this._createDaysOfPreMonth($(daysContainer), year, month, firstDayWeek);
                _this._createDaysOfCurrMonth($(daysContainer), year, month, daysOfMonth);
                _this._createDaysOfNextMonth($(daysContainer), year, month, totalsDays);
            })
        },

        /**
         * 创建day_btn
         * @param $daysContainer
         * @param date
         * @param day
         * @param dayOfWeek 当前日期星期几
         * @param type
         * @private
         */
        _createDayBtn($daysContainer, date, day, dayOfWeek,type) {
            let $dayContainer = $('<div>');
            $dayContainer.addClass(this._defaultClasses.dayContainer);
            $dayContainer.attr('data-date-value', date);

            let $dayBtn = $('<button>');
            $dayBtn.addClass(this._defaultClasses.dayBtn);
            $dayBtn.addClass(type == 'pre' ? this._defaultClasses.dayBtnPreMonth : '');
            $dayBtn.addClass(dayOfWeek == 0 || dayOfWeek == 6 ? this._defaultClasses.dayBtnWeekDay : '');
            $dayBtn.text(day);

            $dayContainer.append($dayBtn);
            $daysContainer.append($dayContainer);
        },

        /**
         * 创建上个月日期
         * @param $daysContainer
         * @param year
         * @param month
         * @param firstDayWeek
         * @private
         */
        _createDaysOfPreMonth($daysContainer, year, month, firstDayWeek) {
            var monday_day = new Date(year, month, 0).getDate() - (firstDayWeek - 1);

            for (let i = firstDayWeek; i > 0; i--, monday_day++) {
                const dateObj = new Date(year, month - 1, monday_day);
                const dayOfWeek = dateObj.getDay();
                const dateFormat = this._formatDateTime(dateObj.getTime(), this.options.format);
                this._createDayBtn($daysContainer, dateFormat, monday_day, dayOfWeek,'pre');
            }
        },

        /**
         * 创建当前月日期
         * @param $daysContainer
         * @param year
         * @param month
         * @param daysOfMonth
         * @private
         */
        _createDaysOfCurrMonth($daysContainer, year, month, daysOfMonth) {
            for (let i = 1; i <= daysOfMonth; i++) {
                const dateObj = new Date(year, month, i);
                const dateFormat = this._formatDateTime(dateObj.getTime(), this.options.format);
                const dayOfWeek = dateObj.getDay();
                this._createDayBtn($daysContainer, dateFormat, i, dayOfWeek, 'curr');
            }
        },

        /**
         * 创建下个月日期
         * @param $daysContainer
         * @param year
         * @param month
         * @param totalsDays
         * @private
         */
        _createDaysOfNextMonth($daysContainer, year, month, totalsDays) {
            const rows = Math.ceil(totalsDays / 7);
            const daysOfNextMonth = 7 * rows - totalsDays;
            for (let i = 1; i <= daysOfNextMonth; i++) {
                const dateObj = new Date(year, month + 1, i);
                const dateFormat = this._formatDateTime(dateObj.getTime(), this.options.format)
                const dayOfWeek = dateObj.getDay();
                this._createDayBtn($daysContainer, dateFormat, i, dayOfWeek,'next');
            }
        },

        /**
         * 初始化事件
         * @private
         */
        _initEvents() {
            var _this = this;

            this.$panel.on('click', function (e) {
                _this._initArrowEvents(e);
            })
        },

        /**
         * 初始化箭头事件
         * @param e
         * @private
         */
        _initArrowEvents(e) {
            const target = e.target;
            const arrow = target.closest(`.${this._defaultClasses.arrow}`);
            if (!arrow) { return; }

            const controlTypes = ['signle'];
            if (controlTypes.includes(this.controlType || this.defaultControlDOMType)) {
                this._changeMonth(arrow);
            }
        },

        _changeMonth(arrow) {
            const arrowTag = $(arrow).attr(this._defaultProperty.arrowPreYear);
            if (!arrowTag) { return; }

            const isChangeMonth = ['pre_month', 'next_month'].includes(arrowTag);
            if (!isChangeMonth) { return; }

            const year = this.selected.selectedYear == null ? this.initYear : this.selected.selectedYear;
            const month = this.selected.selectedMonth == null ? this.initMonth : this.selected.selectedMonth;
            const initDate = new Date(year, month, 1);
            const jump = {
                pre_month: () => initDate.setMonth(initDate.getMonth() - 1),
                next_month: () => initDate.setMonth(initDate.getMonth() + 1)
            };
            jump[arrowTag]();

            this.selected.selectedYear = initDate.getFullYear();
            this.selected.selectedMonth = initDate.getMonth();

            this._visibilityHeader();
            this._createDays();
        },

        /**
         * 解析组件DOM
         * @private
         */
        _DOMParser(template) {
            var _this = this;

            const componentsDOM = {
                YearArrowPrev: _this._getDOMS._getYearArrowPrevDOM,
                MonthArrowPrev: _this._getDOMS._getMonthArrowPrevDOM,
                YearArrowNext: _this._getDOMS._getYearArrowNextDOM,
                MonthArrowNext: _this._getDOMS._getMonthArrowNextDOM,
                Year: _this._getDOMS._getYearDOM,
                Month: _this._getDOMS._getMonthDOM,
                Weeks: _this._getDOMS._getWeeksDOM,
                Days: _this._getDOMS._getDaysDOM
            };

            const getComponent = (pattern) => componentsDOM[pattern];

            return template.replace(/<# (.*?) #>/g, (_, p1) => {
                const component = getComponent(p1.replace(/[\s\n\t]/g, ""));
                return component ? component(this) : "";
            }).replace(/[\n\t]/g, "");
        },

        /**
         * 格式化月份
         * @param month
         * @returns {string}
         * @private
         */
        _formatMonth(month) {
            return month + 1 < 10 ? `0${month + 1}` : `${month + 1}`;
        },

        /**
         * 格式化日份
         * @param day
         * @returns {string}
         * @private
         */
        _formatDay(day) {
            return day < 10 ? `0${day}` : `${day}`;
        }
    })

    /* 时间控件核心代码 */
    $.extend(true, $.dateTime, {
        create(props) {
            if (!props.id) {
                return;
            }

            let DOMTemplate = $.dateTime.prototype._getInputDOMTemplate[props.type || this.defaultControlDOMType]();
            $(props.id).html(DOMTemplate);
        },

        init(node, props) {
            var oDetail = new $.dateTime(node, props);
            return oDetail;
        }
    })
})(jQuery)